package cn.lg.soar.common.util.current;

import cn.lg.soar.common.util.data.SecureRandomUtil;
import cn.lg.soar.common.util.token.LoginInfo;

import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author luguoxiang 469599794@qq.com
 * @Date: 2025/5/17 12:51
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
public class CurrentTokenInfo implements ICurrentUser {

    final static Base64.Decoder DECODER = Base64.getUrlDecoder();
    final static Base64.Encoder ENCODER = Base64.getUrlEncoder();

    /**
     * 用户id
     */
    private long userId;

    /**
     * 用户类型
     */
    private int userType;

    /**
     * 当前租户
     */
    private Integer currentTenantId;

    private long tokenId;

    private int clientType;

    @Override
    public Long getId() {
        return userId;
    }

    @Override
    public Integer getUserType() {
        return userType;
    }

    @Override
    public Integer getCurrentTenantId() {
        return currentTenantId;
    }

    @Override
    public long getTokenId() {
        return tokenId;
    }

    @Override
    public Integer getClientType() {
        return clientType;
    }

    public static CurrentTokenInfo create(long tokenId, LoginInfo loginInfo) {
        CurrentTokenInfo info = new CurrentTokenInfo();
        info.tokenId = tokenId;
        info.userId = loginInfo.getUserId();
        info.currentTenantId = loginInfo.getTenantId();
        info.userType = loginInfo.getUserType();
        info.clientType = loginInfo.getClientType();
        return info;
    }

    public static CurrentTokenInfo valueOf(String payload) {
        byte[] bytes = DECODER.decode(payload.getBytes(StandardCharsets.UTF_8));
        CurrentTokenInfo info = new CurrentTokenInfo();
        info.tokenId = bytesToLong(bytes, 0);
        info.userId = bytesToLong(bytes, 8);
        info.currentTenantId = bytesToInt(bytes, 16);
        info.userType = bytes[20];
        info.clientType = bytes[21];
        return info;
    }

    @Override
    public String toString() {
        byte[] bytes = new byte[54];
        longToBytes(tokenId, bytes, 0);
        longToBytes(userId, bytes, 8);
        intToBytes(currentTenantId, bytes, 16);
        bytes[20] = (byte) userType;
        bytes[21] = (byte) clientType;
        byte[] random = SecureRandomUtil.getBytes(32);
        System.arraycopy(random, 0, bytes, 22, 32);
        return ENCODER.encodeToString(bytes);
    }

    private static void longToBytes(long l, byte[] bytes, int offset) {
        bytes[offset] = (byte) (l >>> 56);
        bytes[offset + 1] = (byte) (l >>> 48);
        bytes[offset + 2] = (byte) (l >>> 40);
        bytes[offset + 3] = (byte) (l >>> 32);
        bytes[offset + 4] = (byte) (l >>> 24);
        bytes[offset + 5] = (byte) (l >>> 16);
        bytes[offset + 6] = (byte) (l >>> 8);
        bytes[offset + 7] = (byte) l;
    }

    private static long bytesToLong(byte[] bytes, int offset) {
        return ((long) (bytes[offset] & 0xFF) << 56)
                | ((long) (bytes[offset + 1] & 0xFF) << 48)
                | ((long) (bytes[offset + 2] & 0xFF) << 40)
                | ((long) (bytes[offset + 3] & 0xFF) << 32)
                | ((long) (bytes[offset + 4] & 0xFF) << 24)
                | ((long) (bytes[offset + 5] & 0xFF) << 16)
                | ((long) (bytes[offset + 6] & 0xFF) << 8)
                | ((long) (bytes[offset + 7] & 0xFF));
    }

    private static void intToBytes(int i, byte[] bytes, int offset) {
        bytes[offset] = (byte) (i >>> 24);
        bytes[offset + 1] = (byte) (i >>> 16);
        bytes[offset + 2] = (byte) (i >>> 8);
        bytes[offset + 3] = (byte) i;
    }

    private static int bytesToInt(byte[] bytes, int offset) {
        return ((bytes[offset] & 0xFF) << 24)
                | ((bytes[offset + 1] & 0xFF) << 16)
                | ((bytes[offset + 2] & 0xFF) << 8)
                | ((bytes[offset + 3] & 0xFF));
    }

}
